package com.ycz.algorithm.utils.queue;

/**
 * @author yancz
 * @ClassName ArrayDeque
 * @description: 双向队列的数组实现
 * @date 2024-11-28 17:01:25
 * @version: 1.0
 */
public class ArrayDeque {

    private int[] nums; // 存储元素

    private int front; // 队首指针，指向队首元素

    private int dequeSize; // 队列长度

    // 队列初始化
    public ArrayDeque(int capacity) {
        this.nums = new int[capacity];
        front = dequeSize = 0;
    }

    // 获取队列容量
    public int capacity() {
        return nums.length;
    }

    // 获取队列长度
    public int size() {
        return dequeSize;
    }

    // 判断队空
    public boolean isEmpty() {
        return size() == 0;
    }

    // 计算环形数组的索引
    private int index(int i) {
        return (i + capacity()) % capacity();
    }

    // 队首入队
    public void pushFirst(int num) {
        if (dequeSize == capacity()) { // 队满判断
            System.out.println("队列已满！");
            return;
        }
        // 队首指针左移一位
        // 取余操作来实现front越过数组头部后回到尾部
        front = index(front - 1);
        nums[front] = num;
        dequeSize++; // 队列长度+1
    }

    // 队尾入队
    public void pushLast(int num) {
        if (dequeSize == capacity()) {
            System.out.println("队列已满！");
            return;
        }
        // 队尾指针
        int rear = index(front + dequeSize);
        nums[rear] = num;
        dequeSize++;
    }

    // 队首出队
    public int popFirst() {
        int num = peekFirst();
        // 队首指针后移一位
        front = index(front + 1);
        dequeSize--;
        return num;
    }

    // 队尾出队
    public int popLast() {
        int num = peekLast();
        dequeSize--;
        return num;
    }

    // 访问队首元素
    public int peekFirst() {
        if (isEmpty()) {
            throw new IndexOutOfBoundsException("队空！");
        }
        return nums[front];
    }

    // 访问队尾元素
    public int peekLast() {
        if (isEmpty()) {
            throw new IndexOutOfBoundsException("队空！");
        }
        // 计算队尾指针
        int last = index(front + dequeSize - 1);
        return nums[last];
    }

    // 转为数组
    public int[] toArray() {
        int[] res = new int[dequeSize];
        for (int i = 0, j = front; i < res.length; i++, j++) {
            res[i] = nums[index(j)];
        }
        return res;
    }

    public static void main(String[] args) {
        ArrayDeque arrayDeque = new ArrayDeque(6);
        // 队尾入队
        arrayDeque.pushLast(1);
        arrayDeque.pushLast(2);
        arrayDeque.pushLast(3);
        // 队首入队
        arrayDeque.pushFirst(4);
        arrayDeque.pushFirst(5);
        commonPrint(arrayDeque);
        // 队首出队
        System.out.println("出队元素：" + arrayDeque.popFirst());
        commonPrint(arrayDeque);
        // 队尾出队
        System.out.println("出队元素：" + arrayDeque.popLast());
        commonPrint(arrayDeque);
    }

    private static void commonPrint(ArrayDeque arrayDeque) {
        int[] arrs = arrayDeque.toArray();
        for (int i : arrs) {
            System.out.print(i + "\t");
        }
        System.out.println();
        System.out.println("队列长度：" + arrs.length);
        System.out.println("队首元素：" + arrayDeque.peekFirst());
        System.out.println("队尾元素：" + arrayDeque.peekLast());
    }


}
